#!/bin/ksh
#
# Kill processes based on their resource consumption.
#
# syntax: 
# <process name>:<cputime|etime|pcpu|vsize>:<warn value>:<max value)>:<notify
# opt>
#
#  where:
#          cputime is in minutes
#          age is in minutes
#          pcpu is in percentage points
#          size is in kilobytes
#
#  notify options:
#          0: Notify mail/page on warn/error thresholds, DONT kill process
#             NOTE: any other value will default to 0 (zero).
#          1: Notify mail/page on warn/error thresholds, AND kill process
#          2: Notify via mail on error threshold, AND kill process
#          3: Kill process without any notification.
#
debug=1
sleeptime=3
kill_plist="dhcpd:etime:1:27:1"
clear

notify () 
{
  case $2 in
    0)
      # Warn/error level and don't kill..
      echo "$1: $3 process id $4 found with $5 $7. Should be less than $6." 
    ;;
    1)
      # Warn/error level and kill..
      echo "$1: $3 process id $4 found with $5 $7. Should be less than $6."
      test $debug -eq 0 && kill $4
    ;;
    2)
      # Warning level only...
      echo "Warning: $3 process id $4 found with $5 $7. Should be less than $6."
      test $debug -eq 0 && kill $4
    ;;
    3)
      # Just kill, don't warn at all..
      test $debug -eq 0 && kill $4
    ;;
  esac
}


while : 
do
  for pline in $kill_plist
  do
    process=`echo $pline | cut -d: -f1`
    process="`echo $process | sed -e \"s/%20/ /g\"`"
    type=`echo $pline | cut -d: -f2`
    value=`echo $pline | awk -F: '{print $3}'`
    errval=`echo $pline | awk -F: '{print $4}'`
    killoption=`echo $pline | awk -F: '{print $5}'`
    if [ "$killoption" = "" ]
    then
        killoption=0
    fi
    
    test $debug -gt 0 && echo "Kill $process processes if $type is greater than $errval"
 
    for pid in `ps -eo pid,comm | egrep "${process}$|${process}:$" | grep -v grep | awk '{print $1}'`
    do
      test $debug -gt 0 && echo "$process pid $pid"
      pid_string=`ps -eo pid,cputime,etime,pcpu,vsize,comm | grep $pid | egrep "${process}$|${process}:$" | grep -v grep`
      case $type in
        "cputime")
          proc_time=`echo $pid_string | awk '{print $2}'`
          fields=`echo $proc_time | awk -F: '{print NF}'`
          proc_time_min=`echo $proc_time | awk -F: '{print $(NF-1)}'`
          if [ $fields -lt 3 ]
          then
            proc_time_hr=0
            proc_time_day=0
          else
            proc_time_hr=`echo $proc_time | awk -F: '{print $(NF-2)}'`
            fields=`echo $proc_time_hr | awk -F- '{print NF}'`
            if [ $fields -ne 1 ]
            then
              proc_time_day=`echo $proc_time_hr | awk -F- '{print $1}'`
              proc_time_hr=`echo $proc_time_hr | awk -F- '{print $2}'`
            else
              proc_time_day=0
            fi
          fi
          curr_cpu_time=`echo "$proc_time_day*1440+$proc_time_hr*60+$proc_time_min" | bc`
          test $debug -gt 0 && echo "Current cpu time for $process pid $pid is $curr_cpu_time minutes"
          #
          # Test the thresholds
          #
          if test $curr_cpu_time -gt $value -a $curr_cpu_time -lt $errval
          then
            notify "Warning" $killoption $process $pid $curr_cpu_time $value "minutes of CPU time"
          elif test $curr_cpu_time -ge $errval
          then
            notify "Error" $killoption $process $pid $curr_cpu_time $value "minutes of CPU time"
          else
            test $debug -gt 0 && echo "process cpu time ok"
          fi
        ;;
        "etime")
          proc_age=`echo $pid_string | awk '{print $3}'`
          fields=`echo $proc_age | awk -F: '{print NF}'`
          proc_age_min=`echo $proc_age | awk -F: '{print $(NF-1)}'`
          if [ $fields -lt 3 ]
          then
            proc_age_hr=0
            proc_age_day=0
          else
            proc_age_hr=`echo $proc_age | awk -F: '{print $(NF-2)}'`
            fields=`echo $proc_age_hr | awk -F- '{print NF}'`
            if [ $fields -ne 1 ]
            then
              proc_age_day=`echo $proc_age_hr | awk -F- '{print $1}'`
              proc_age_hr=`echo $proc_age_hr | awk -F- '{print $2}'`
            else
              proc_age_day=0
            fi
          fi
          curr_age=`echo "$proc_age_day*1440+$proc_age_hr*60+$proc_age_min" | bc`
          test $debug -gt 0 && echo "Current age of $process pid $pid is $curr_age minutes"
          #
          # Test the thresholds
          #
          if test $curr_age -gt $value -a $curr_age -lt $errval
          then
            notify "Warning" $killoption $process $pid $curr_age $value "minutes of elapsed time"
          elif test $curr_age -ge $errval
          then
            notify "Error" $killoption $process $pid $curr_age $value "minutes of elapsed time"
          else
            test $debug -gt 0 && echo "process age ok"
          fi
        ;;
        "pcpu")
          curr_proc_cpu=`echo $pid_string | awk '{print $4}' | awk -F. '{print $1}'`
          test $debug -gt 0 && echo "Current percent cpu of $process pid $pid is $curr_proc_cpu"
          #
          # Test the thresholds
          #
          if test $curr_proc_cpu -gt $value -a $curr_proc_cpu -lt $errval
          then
            notify "Warning" $killoption $process $pid $curr_proc_cpu $value "percent of the CPU"
          elif test $curr_proc_cpu -ge $errval
          then
            notify "Error" $killoption $process $pid $curr_proc_cpu $value "percent of the CPU"
          else
            test $debug -gt 0 && echo "process cpu percent ok"
          fi
        ;;
        "vsize")
          curr_proc_size=`echo $pid_string | awk '{print $5}'`
          test $debug -gt 0 && echo "Current size of $process pid $pid is $curr_proc_size"
          #
          # Test the thresholds
          #
          if test $curr_proc_size -gt $value -a $curr_proc_size -lt $errval
          then
            notify "Warning" $killoption $process $pid $curr_proc_size $value "blocks of virtual size"
          elif test $curr_proc_size -ge $errval
          then
            notify "Error" $killoption $process $pid $curr_proc_size $value "blocks of virtual size"
          else
            test $debug -gt 0 && echo "process virtual size ok"
          fi
        ;;
      esac
    done
  done
  sleep $sleeptime
  clear
done
